package com.xuecheng.orders.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.utils.IdWorkerUtils;
import com.xuecheng.base.utils.QRCodeUtil;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xuecheng.orders.config.AlipayConfig;
import com.xuecheng.orders.config.PayNotifyConfig;
import com.xuecheng.orders.feignclient.CoursePublish;
import com.xuecheng.orders.feignclient.GetCoursePriceClient;
import com.xuecheng.orders.mapper.XcOrdersGoodsMapper;
import com.xuecheng.orders.mapper.XcOrdersMapper;
import com.xuecheng.orders.mapper.XcPayRecordMapper;
import com.xuecheng.orders.model.dto.AddOrderDto;
import com.xuecheng.orders.model.dto.PayRecordDto;
import com.xuecheng.orders.model.dto.PayStatusDto;
import com.xuecheng.orders.model.po.XcOrders;
import com.xuecheng.orders.model.po.XcOrdersGoods;
import com.xuecheng.orders.model.po.XcPayRecord;
import com.xuecheng.orders.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    XcOrdersMapper ordersMapper ;

    @Autowired
    XcOrdersGoodsMapper ordersGoodsMapper ;

    @Autowired
    XcPayRecordMapper xcPayRecordMapper ;

    @Autowired
    OrderServiceImpl currentProxy ;

    @Autowired
    MqMessageService mqMessageService;

    @Autowired
    GetCoursePriceClient getCoursePriceClient ;

    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;

    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;

    @Value("${pay.qrcodeurl}")
    String qrcodeurl ;

    @Autowired
    RabbitTemplate rabbitTemplate ;

    @Override
    public PayRecordDto queryPayResult(String payNo) {
//        调用支付宝的接口查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);

        currentProxy.saveAliPayStatus(payStatusDto) ;

        XcPayRecord payRecordByPayno = getPayRecordByPayno(payNo);

        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecordByPayno,payRecordDto);
        return payRecordDto;
    }


    //保存支付状态结果
    @Override
    @Transactional
    public void saveAliPayStatus(PayStatusDto payStatusDto){
        String payNo = payStatusDto.getOut_trade_no();
        XcPayRecord payRecordByPayno = getPayRecordByPayno(payNo);
        if(StringUtils.isEmpty(payRecordByPayno)){
            XueChengPlusException.cast("找不到相关的支付记录");
        }
        //支付状态
        Long orderId = payRecordByPayno.getOrderId();
        XcOrders xcOrders = ordersMapper.selectById(orderId);
        if(StringUtils.isEmpty(xcOrders)){
            XueChengPlusException.cast("找不到相关的订单");
        }
        String status = payRecordByPayno.getStatus();
        if("601002".equals(status)){
            //如果数据库状态成功，不在处理
            return;
        }

        String trade_status = payStatusDto.getTrade_status();//支付宝查询到的支付结果
        if(trade_status.equals("TRADE_SUCCESS")){
            payRecordByPayno.setStatus("601002");
//            支付宝订单
            payRecordByPayno.setOutPayNo(payStatusDto.getTrade_no());

            payRecordByPayno.setOutPayChannel("ALipay");

            payRecordByPayno.setPaySuccessTime(LocalDateTime.now());

            xcPayRecordMapper.updateById(payRecordByPayno);

//            更新订单表的状态为支付成功
            xcOrders.setStatus("600002");

            ordersMapper.updateById(xcOrders);


//            将消息写到数据库
            MqMessage mqMessage = mqMessageService.addMessage("payresult_notify", xcOrders.getOutBusinessId(), xcOrders.getOrderType(), null);

//            发送消息
            notifyPayResult(mqMessage);
        }
    }

    @Override
    public void notifyPayResult(MqMessage message) {

        String jsonString = JSON.toJSONString(message);

//        创建持久化消息
        Message messageObj = MessageBuilder.withBody(jsonString.getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
        Long id = message.getId();
//        指定回调方法
        CorrelationData correlationData = new CorrelationData(id.toString());

        correlationData.getFuture().addCallback(result -> {
            if(result.isAck()){
//                消息成功发送到交换机
                log.debug("发送消息成功：{}",jsonString);
                //将消息从数据库表删除
                mqMessageService.completed(id);

            }else {
                log.debug("发送消息失败：{}",jsonString);
            }
        },ex -> {
            log.debug("发送消息异常：{}",jsonString);
        });
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",messageObj,correlationData);
    }


    public PayStatusDto queryPayResultFromAlipay(String payNo){
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
//        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipaydev.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no",payNo);
//bizContent.put("trade_no", "2014112611001004680073956707");
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        String body = null ;
        try {
            response = alipayClient.execute(request);
            if(!response.isSuccess()){
                XueChengPlusException.cast("请求支付查询结果失败");
            }
            body = response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            XueChengPlusException.cast("请求支付查询支付结果异常");
        }

//        Map<String,Map<String,String>> map1 = JSON.parseObject(body, Map.class);
//        Map<String, String> map2 = map1.get(0);
//        JSON.parseObject(map2.get(""), Map.class);
        Map<String,String> map = JSON.parseObject(body, Map.class);
//        String s = map.get("trade_status");
        Object obj = map.get("alipay_trade_query_response");

        Map<String,String> resultMap = JSON.parseObject(JSON.toJSONString(obj), new TypeReference<Map<String, String>>() {
        });

        String trade_no = resultMap.get("trade_no");
        String trade_status = resultMap.get("trade_status");
        String total_amount = resultMap.get("total_amount");
        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_no(trade_no);
        payStatusDto.setTrade_status(trade_status);
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTotal_amount(total_amount);

        return payStatusDto ;
//        System.out.println(body);
////        if(response.isSuccess()){
////            System.out.println("调用成功");
////        } else {
////            System.out.println("调用失败");
////        }
    }


    @Override
    public XcPayRecord getPayRecordByPayno(String payNo) {
        XcPayRecord xcPayRecord = xcPayRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        return xcPayRecord;
    }

    @Transactional
    @Override
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto){


//        获取价格
        String orderDetail = addOrderDto.getOrderDetail();
//            XcOrdersGoods xcOrdersGoods = JSON.parseObject(orderDetail, XcOrdersGoods.class);
        List list = JSON.parseObject(orderDetail, List.class);
        String goodsId = null ;
        for (Object xcOrdersGoods : list) {

            //userMap = new BeanMap(bSysUser);
            Map<String,String> map  = JSON.parseObject(JSON.toJSONString(xcOrdersGoods), new TypeReference<Map<String, String>>() {
            });

//                Map<String,String> map = JSON.parseObject(xcOrdersGoods, Map.class);
            goodsId = map.get("goodsId");
        }

//            Map<String,String> map = JSON.parseObject(orderDetail, Map.class);

//            XcOrdersGoods xcOrdersGoods = list.get(0);
//            String goodsId = xcOrdersGoods1.getGoodsId();
        CoursePublish coursepublish = getCoursePriceClient.getCoursepublish(Long.parseLong(goodsId));
        Float price =coursepublish.getPrice() ;

        addOrderDto.setTotalPrice(price);




//        插入订单表。订单主表，订单明细表
        XcOrders xcOrders = saveXcOrders(userId, addOrderDto);

//        插入支付记录
        XcPayRecord payRecord = createPayRecord(xcOrders);
        Long payNo = payRecord.getPayNo();

//        生成二维码
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        String url = String.format(qrcodeurl, payNo);
        String qrCode = null ;
        try {
            qrCode = qrCodeUtil.createQRCode(url, 200, 200);
        } catch (IOException e) {
            XueChengPlusException.cast("生成二维码出错");
        }

        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord,payRecordDto);
        payRecordDto.setQrcode(qrCode);

        return payRecordDto;
    }

    public XcOrders saveXcOrders(String userId, AddOrderDto addOrderDto){
//        插入订单表订单主表。订单明细表
//    进行幂等性判断，同一选课记录只能有一个订单
        XcOrders xcOrders = getOrderByBusinessId(addOrderDto.getOutBusinessId());
        if(!StringUtils.isEmpty(xcOrders)){
            return xcOrders ;
        }
        //        插入订单表订单主表。订单明细表
        xcOrders = new XcOrders();
        //雪花算法生成订单号
        xcOrders.setId(IdWorkerUtils.getInstance().nextId());
        xcOrders.setTotalPrice(addOrderDto.getTotalPrice());
        xcOrders.setCreateDate(LocalDateTime.now());
        xcOrders.setStatus("600001");//未支付
        xcOrders.setUserId(userId);
        xcOrders.setOrderType("60201");
        xcOrders.setOrderName(addOrderDto.getOrderName());
        xcOrders.setOrderDetail(addOrderDto.getOrderDetail());
        xcOrders.setOrderDescrip(addOrderDto.getOrderDescrip());
        xcOrders.setOutBusinessId(addOrderDto.getOutBusinessId());//选课记录id
        int insert = ordersMapper.insert(xcOrders);
        if(insert<=0){
            XueChengPlusException.cast("添加订单失败");
        }

        Long orderId = xcOrders.getId();
//        插入订单明细表
//        将前端转入的json串转成list
        String orderDetailJson = addOrderDto.getOrderDetail();
        List<XcOrdersGoods> xcOrdersGoods = JSON.parseArray(orderDetailJson, XcOrdersGoods.class);
        for (XcOrdersGoods xcOrdersGood : xcOrdersGoods) {
            xcOrdersGood.setOrderId(orderId);
            xcOrdersGood.setGoodsPrice(addOrderDto.getTotalPrice());
            ordersGoodsMapper.insert(xcOrdersGood);
        }

        return xcOrders ;
    }
    //根据业务id查询订单
    public XcOrders getOrderByBusinessId(String businessId) {
        XcOrders orders = ordersMapper.selectOne(new LambdaQueryWrapper<XcOrders>().eq(XcOrders::getOutBusinessId, businessId));
        return orders;
    }
//保存支付记录
    public XcPayRecord createPayRecord(XcOrders orders){
        Long orderId = orders.getId();
        XcOrders xcOrders = ordersMapper.selectById(orderId);

        if(StringUtils.isEmpty(xcOrders)){
            XueChengPlusException.cast("订单不存在");
        }
        String status = xcOrders.getStatus();
        if("601002".equals(status)){
            XueChengPlusException.cast("此订单已支付");
        }

        XcPayRecord xcPayRecord = new XcPayRecord();
        xcPayRecord.setPayNo(IdWorkerUtils.getInstance().nextId());
        xcPayRecord.setOrderId(orderId);
        xcPayRecord.setOrderName(xcOrders.getOrderName());
        xcPayRecord.setTotalPrice(orders.getTotalPrice());
        xcPayRecord.setCurrency("CNY");
        xcPayRecord.setCreateDate(LocalDateTime.now());
        xcPayRecord.setStatus("601001");//未支付
        xcPayRecord.setUserId(orders.getUserId());
        int insert = xcPayRecordMapper.insert(xcPayRecord);
        if(insert<=0){
            XueChengPlusException.cast("插入支付记录失败");
        }
        return xcPayRecord;
    }
}
